import random
import re
from datetime import datetime

from flask import request, abort, current_app, make_response, json, jsonify, session

from info import redis_store, constants, db
from info.libs.yuntongxun.sms import CCP
from info.models import User
from info.utils.response_code import RET
from . import passport_blu
from info.utils.captcha.captcha import captcha


@passport_blu.route("/logout")
def logout():
    """退出登录
    清除session中保存的登录信息
    :return:
    """
    session.pop('user_id', None)
    session.pop('nick_name', None)
    session.pop('mobile', None)
    # 要清除is_admin的值,不然先登录的管理员，会保存到session中，在登录普通用户也拥有这个值
    session.pop('is_admin', None)

    return jsonify(errno=RET.OK, errmsg='退出成功！')


@passport_blu.route('/login', methods=['POST'])
def login():
    """登录
    1.获取用户名和密码
    2.判断参数是否齐全
    3.判断用户是否存在
    4.用户存在，校验密码
    5.保存登录状态
    6.响应
    :return:
    """

    # 1.获取用户名和密码
    params_dict = request.json
    mobile = params_dict.get('mobile')
    password = params_dict.get('password')

    # 2.判断参数是否齐全
    if not all([mobile, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不足！')
    if not re.match(r'1[3568]\d{9}', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式错误！')

    # 3.判断用户是否存在
    try:
        user = User.query.filter(User.mobile == mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库查询错误！')

    if not user:
        return jsonify(errno=RET.NODATA, errmsg='用户不存在！')

    # 4.用户存在，校验密码
    if not user.check_password(password):
        return jsonify(errno=RET.PWDERR, errmsg='用户名或密码错误！')

    # 5.保存登录状态
    session['user_id'] = user.id
    session['nick_name'] = user.nick_name
    session['mobile'] = user.mobile

    # 记录用户最后一次登录时间
    user.last_login = datetime.now()
    # try:
    #     db.session.commit()
    # except Exception as e:
    #     db.session.rollback()
    #     current_app.logger.error(e)
    #     return jsonify(errno=RET.DBERR, errmsg='数据库查询错误！')

    # 6.响应
    return jsonify(errno=RET.OK, errmsg='登录成功！')


@passport_blu.route('/register', methods=['POST'])
def register():
    """注册
    1.获取手机号，短信验证码，密码
    2.对数据进行判断
    3.从redis中取出短信验证码
    4.进行验证码对比
    5.初始化 user 模型，并设置数据并添加到数据库
    6.保存当前用户的登录状态
    7.返回注册的结果
    :return:
    """

    # 1.获取手机号，短信验证码，密码
    params_dict = request.json
    mobile = params_dict.get('mobile')
    sms_code = params_dict.get('smscode')
    password = params_dict.get('password')

    # 2.对数据进行判断
    if not all([mobile, sms_code, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不足！')
    # 判断手机号类型
    if not re.match(r'1[3568]\d{9}', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式错误！')

    # 3.从redis中取出短信验证码
    try:
        redis_code = redis_store.get('SES_'+mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库查询错误！')

    # 判断验证码是否过期
    if not redis_code:
        return jsonify(errno=RET.NODATA, errmsg='短信验证码过期！')

    # 4.进行验证码对比
    if sms_code != redis_code:
        return jsonify(errno=RET.PARAMERR, errmsg='短信验证码输入错误！')

    # 5.初始化 user 模型，并设置数据并添加到数据库
    user = User()
    user.mobile = mobile
    # 暂时没有昵称，使用手机号代替
    user.nick_name = mobile
    # 记录用户最后一次登录时间
    user.last_login = datetime.now()
    # 密码加密处理
    user.password = password

    # 设置数据并添加到数据库
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库错误！')

    # 6.保存当前用户的登录状态
    session['user_id'] = user.id
    session['nick_name'] = user.nick_name
    session['mobile'] = user.mobile

    # 7.返回注册的结果
    return jsonify(errno=RET.OK, errmsg='注册成功！')


@passport_blu.route('/sms_code', methods=['POST'])
def send_sms_code():
    """发送验证码
    1.获取数据: 手机号 图片验证码内容 验证码编号（随机值）
    2.判断获取数据是否为空，类型是否正确
    3.从redis中获取对应的验证码编号
    4.与用户提交数据进行比对,如果不一致，返回验证码输入错误
    5.如果一致，生成随机的6位验证码
    6.发送验证码,验证发送是否成功
    7.保存验证码到redis
    8.告知发送结果
    :return:
    """

    # 1.获取数据: 手机号 图片验证码内容 验证码编号（随机值）
    # params_dict = json.loads(request.data)
    params_dict = request.json
    mobile = params_dict.get('mobile')
    image_code = params_dict.get('image_code')
    image_code_id = params_dict.get('image_code_id')

    # 2.判断获取数据是否为空，类型是否正确
    if not all([mobile, image_code, image_code_id]):
        # return json.dumps(errno=RET.PARAMERR, errmsg='参数不足！')
        return jsonify(errno=RET.PARAMERR, errmsg='参数不足！')
    # 判断手机号类型
    if not re.match(r'1[3568]\d{9}', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式错误！')

    # 3.从redis中获取对应的验证码编号
    try:
        redis_image_code_id = redis_store.get('ImageCodeId_'+image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库查询错误！')

    # 判断验证码是否过期
    if not redis_image_code_id:
        return jsonify(errno=RET.NODATA, errmsg='验证码过期，点击刷新！')

    # 4.与用户提交数据进行比对,如果不一致，返回验证码输入错误
    if image_code.upper() != redis_image_code_id.upper():
        return jsonify(errno=RET.PARAMERR, errmsg='图片验证码输入错误！')

    # 5.如果一致，生成随机的6位验证码
    random_code = "%06d" % random.randint(0, 999999)
    # print(random_code)

    # 6.发送验证码,验证发送是否成功
    result = CCP().send_template_sms(mobile, [random_code, constants.SMS_CODE_REDIS_EXPIRES / 100], "1")

    if result == -1:
        return jsonify(errno=RET.THIRDERR, errmsg='验证码发送失败！')

    # 7.保存验证码到redis
    try:
        redis_store.set('SES_'+mobile, random_code, constants.SMS_CODE_REDIS_EXPIRES)  # 第三个参数过期时间
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库查询错误！')

    # 8.告知发送结果
    return jsonify(errno=RET.OK, errmsg='验证码发送成功！')


@passport_blu.route('/image_code')
def gte_image_code():
    """
    生成图片验证码并返回
    1. 取出参数
    2. 判断是否有值
    3. 生成图片验证码
    4. 保存图片验证码的文字到redis中去
    5. 返回图片验证码
    """

    # 1. 取出参数
    # args: 取到？后面的参数
    image_code_id = request.args.get('imageCodeId', None)
    #  2. 判断是否有值
    if not image_code_id:
        return abort(403)
    # 3. 生成图片验证码
    name, text, image = captcha.generate_captcha()
    # 4. 保存图片验证码的文字到redis中去
    try:
        redis_store.set('ImageCodeId_'+image_code_id, text, constants.IMAGE_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
        abort(500)
    # 5. 返回图片验证码
    response = make_response(image)
    # 设置数据类型
    response.headers['Content-Type'] = 'image/jpg'
    return response